﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Checksums;

namespace NetDisk_WebService.Common
{
    public class Zip
    {
        public Zip()
        {
 
        }

        /// <summary>
        /// 解压功能(解压压缩文件到指定目录)
        /// </summary>
        /// <param name="FileToUpZip">待解压的文件</param>
        /// <param name="ZipedFolder">指定解压目标目录</param>
        public static void UnZip(string FileToUpZip, string ZipedFolder,string password)
        {
            if (!File.Exists(FileToUpZip))
            {
                return;
            }

            if (!Directory.Exists(ZipedFolder))
            {
                Directory.CreateDirectory(ZipedFolder);
            }

            ZipInputStream s = null;
            ZipEntry theEntry = null;

            string fileName;
            FileStream streamWriter = null;
            try
            {
                s = new ZipInputStream(File.OpenRead(FileToUpZip));
                s.Password = password;
                while ((theEntry = s.GetNextEntry()) != null)
                {
                    if (theEntry.Name != String.Empty)
                    {
                        fileName = Path.Combine(ZipedFolder, theEntry.Name);
                        /**/
                        ///判断文件路径是否是文件夹
                        if (fileName.EndsWith("/") || fileName.EndsWith("\\"))
                        {
                            Directory.CreateDirectory(fileName);
                            continue;
                        }

                        streamWriter = File.Create(fileName);
                        int size = 2048;
                        byte[] data = new byte[2048];
                        while (true)
                        {
                            size = s.Read(data, 0, data.Length);
                            if (size > 0)
                            {
                                streamWriter.Write(data, 0, size);
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }
            }
            finally
            {
                if (streamWriter != null)
                {
                    streamWriter.Flush();
                    streamWriter.Close();
                    streamWriter = null;
                }
                if (theEntry != null)
                {
                    theEntry = null;
                }
                if (s != null)
                {
                    s.Close();
                    s = null;
                }
                GC.Collect();
                GC.Collect(1);
                
            }
        }





        /// <summary>
        /// 压缩文件
        /// </summary>
        /// <param name="FileToZip">要进行压缩的文件名</param>
        /// <param name="ZipedFile">压缩后生成的压缩文件名</param>
        /// <returns></returns>
        public static bool ZipFile(string FileToZip, string ZipedFile,string password)
        {
            //如果文件没有找到，则报错
            //FileStream fs = null;
            FileStream ZipFile = null;
            FileStream fs = null;
            ZipOutputStream ZipStream = null;
            ZipEntry ZipEntry = null;
            Crc32 crc = new Crc32();

            bool res = true;
            try
            {
                string[] filenames;
                filenames = Directory.GetFiles(FileToZip);
                //先删除同名的压缩文件
                if (File.Exists(ZipedFile))
                {
                    System.IO.File.Delete(ZipedFile);
                }
                foreach (string file in filenames)
                {
                    //打开压缩文件
                    fs = File.OpenRead(file);
                    byte[] buffer = new byte[fs.Length];
                    fs.Read(buffer, 0, buffer.Length);

                    if (!File.Exists(ZipedFile))
                    {
                        ZipFile = File.Create(ZipedFile);
                        ZipStream = new ZipOutputStream(ZipFile);
                        ZipStream.Password = password;
                    }
                    ZipEntry = new ZipEntry(Path.GetFileName(file));
                    ZipEntry.DateTime = DateTime.Now;

                    ZipEntry.Size = fs.Length;
                    crc.Reset();
                    crc.Update(buffer);

                    ZipEntry.Crc = crc.Value;
                    ZipStream.PutNextEntry(ZipEntry);
                    ZipStream.SetLevel(9);
                    ZipStream.Write(buffer, 0, buffer.Length);
                    fs.Close();
                }

            }
            catch
            {
                res = false;
            }
            finally
            {
                if (ZipEntry != null)
                {
                    ZipEntry = null;
                }
                if (ZipStream != null)
                {
                    ZipStream.Flush();
                    ZipStream.Finish();
                    ZipStream.Close();
                    ZipStream.Dispose();
                    ZipStream = null;
                }
                if (ZipFile != null)
                {
                    ZipFile.Close();
                    ZipFile = null;
                }
                GC.Collect();
                GC.Collect(1);
            }

            return res;
        }



        /// <summary>
        /// Zips the specified zip path.
        /// </summary>
        /// <param name="strZipPath">The zip path.</param>
        /// <param name="strZipTopDirectoryPath">The zip top directory path.</param>
        /// <param name="intZipLevel">The zip level.</param>
        /// <param name="strPassword">The password.</param>
        /// <param name="filesOrDirectoriesPaths">The files or directories paths.</param>
        /// <param name="subsectionLoad">是否分段读取</param>
        /// <returns></returns>
        public static bool CreateZip(string strZipPath, string strZipTopDirectoryPath, int intZipLevel, string strPassword, List<string> filesOrDirectoriesPaths, bool subsectionLoad)
        {
            try
            {
                List<string> AllFilesPath = new List<string>();
                if (filesOrDirectoriesPaths.Count > 0) // get all files path
                {
                    for (int i = 0; i < filesOrDirectoriesPaths.Count; i++)
                    {
                        if (File.Exists(filesOrDirectoriesPaths[i]))
                        {
                            AllFilesPath.Add(filesOrDirectoriesPaths[i]);
                        }
                        else if (Directory.Exists(filesOrDirectoriesPaths[i]))
                        {
                            GetDirectoryFiles(filesOrDirectoriesPaths[i], AllFilesPath);
                        }
                    }
                }

                if (AllFilesPath.Count > 0)
                {

                    ZipOutputStream zipOutputStream = new ZipOutputStream(File.Create(strZipPath));
                    zipOutputStream.SetLevel(intZipLevel);
                    zipOutputStream.Password = strPassword;

                    for (int i = 0; i < AllFilesPath.Count; i++)
                    {
                        string strFile = AllFilesPath[i].ToString();
                        try
                        {
                            if (strFile.Substring(strFile.Length - 1) == "\\") //folder                            
                            {
                                string strFileName = strFile.Replace(strZipTopDirectoryPath, "");
                                //if (strFileName.StartsWith(""))
                                //{
                                //    strFileName = strFileName.Substring(1);
                                //}
                                ZipEntry entry = new ZipEntry(strFileName);
                                entry.DateTime = DateTime.Now;
                                zipOutputStream.PutNextEntry(entry);
                            }
                            else //file
                            {
                                FileStream fs = File.OpenRead(strFile);

                                string strFileName = strFile.Replace(strZipTopDirectoryPath, "");
                                //if (strFileName.StartsWith(""))
                                //{
                                //    strFileName = strFileName.Substring(1);
                                //}
                                ZipEntry entry = new ZipEntry(strFileName);
                                entry.DateTime = DateTime.Now;
                                zipOutputStream.PutNextEntry(entry);

                                if (subsectionLoad)//分段读取,每次读取400KB
                                {
                                    int offset = 409600;
                                    for (long j = 0; j < fs.Length; j += offset)
                                    {
                                        int byteLength = offset;
                                        if ((fs.Length - j) < offset)
                                        {
                                            byteLength = (int)(fs.Length - j);
                                        }

                                        byte[] buffer = new byte[byteLength];
                                        fs.Read(buffer, 0, byteLength);
                                        zipOutputStream.Write(buffer, 0, byteLength);
                                    }
                                }
                                else//一次读取
                                {
                                    byte[] buffer = new byte[fs.Length];
                                    fs.Read(buffer, 0, buffer.Length);
                                    zipOutputStream.Write(buffer, 0, buffer.Length);
                                }
                                fs.Close();
                                fs.Dispose();
                            }
                        }
                        catch
                        {
                            continue;
                        }
                    }

                    zipOutputStream.Finish();
                    zipOutputStream.Close();

                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Gets the directory files.
        /// </summary>
        /// <param name="strParentDirectoryPath">The parent directory path.</param>
        /// <param name="AllFilesPath">All files path.</param>
        private static void GetDirectoryFiles(string strParentDirectoryPath, List<string> AllFilesPath)
        {
            string[] files = Directory.GetFiles(strParentDirectoryPath);
            for (int i = 0; i < files.Length; i++)
            {
                AllFilesPath.Add(files[i]);
            }
            string[] directorys = Directory.GetDirectories(strParentDirectoryPath);
            for (int i = 0; i < directorys.Length; i++)
            {
                GetDirectoryFiles(directorys[i], AllFilesPath);
            }
            if (files.Length == 0 && directorys.Length == 0) //empty folder
            {
                AllFilesPath.Add(strParentDirectoryPath + "\\");
            }
        }

        



    }
}
